﻿//
// Created by 抑~风 on 2022/10/26.
//
#include "threadpool.h"
#include<iostream>
#include<thread>
#include<cassert>
namespace CWJ {
    // 为线程编号
    uint32_t Thread::nowId = 0;

    const size_t ThreadPool::DEFAULT_INIT_THREAD_NUM = 4;
    const size_t ThreadPool::DEFAULT_MAX_THREAD_NUM = 8;// 后面改为核心数
    const size_t ThreadPool::DEFAULT_MAX_TASK_NUM_ = 1024;
    const ThreadPool::ThreadPoolMode ThreadPool::DEFAULT_MODE = ThreadPoolMode::FIXED;
    const size_t ThreadPool::DEFAULT_CACHEWAIT_MILLISECONDES = 1000;

    ThreadPool::ThreadPool(ThreadPoolMode mode, size_t initThreadNum,
                            size_t maxThreadNum, size_t maxTaskNum):
                           mode(mode)
                           ,initThreadNum_(initThreadNum)
                           ,maxThreadNum_(maxThreadNum)
                           ,maxTaskNum_(maxTaskNum)
    {
        this->cache_wait_milliseconds = ThreadPool::DEFAULT_CACHEWAIT_MILLISECONDES;
    }
    size_t ThreadPool::getDefaultInitThreadNum() {
        return DEFAULT_INIT_THREAD_NUM;
    }

    size_t ThreadPool::getDefaultMaxThreadNum() {
        return DEFAULT_MAX_THREAD_NUM;
    }


    size_t ThreadPool::getDefaultMaxTaskNum() {
        return DEFAULT_MAX_TASK_NUM_;
    }

    ThreadPool::ThreadPoolMode ThreadPool::getDefaultMode() {
        return DEFAULT_MODE;
    }


    bool ThreadPool::addNewThread() {
        std::unique_lock<std::mutex> lock(this->threadQue_mx_lock);
        if (this->nowThreadNum_ >= this->maxThreadNum_) {
            return false;
        }
        this->add_inited_Thread(Thread::getNowId());
        return true;
    }

    void ThreadPool::add_inited_Thread(uint32_t id) {

        this->threadQue_[id ] = (std::make_shared<Thread>([this, id] { threadFunc(id); }));
        this->nowThreadNum_++;
        this->threadQue_[id]->start();
    }

    void ThreadPool::submitTask_help(ThreadPool::TaskFunc task) {
        std::unique_lock<std::mutex>lock(this->mx_lock);
        while (this->nowTaskNum_ >= this->maxTaskNum_) {
            this->notFull_cv.wait(lock);
            this->addNewThread();
        }
        this->taskQue_.push(task);
        this->nowTaskNum_++;
        this->notEmpty_cv.notify_all();
    }

    void ThreadPool::start() {
        uint32_t tmp = 0;
        for(int i=0;i<this->initThreadNum_;i++){
            this->add_inited_Thread(Thread::getNowId());
        }
        this->isRunning = true;
    }

    void ThreadPool::destroyThread(uint32_t id){
        this->threadQue_.erase(id);
    }


     void ThreadPool::threadFunc(uint32_t id) {
        auto lastTime = std::chrono::high_resolution_clock::now(),nowTime = lastTime;
        while(true){
            ThreadPool::TaskFunc task;
            {
                std::unique_lock<std::mutex>lock(this->mx_lock);
                while (this->nowTaskNum_ <= 0) {
                    if (isEnd)   break;
                    if (this->nowThreadNum_ > this->initThreadNum_) {
                        // 叫醒这个线程的可能是有新任务了，也可能是超时了，所以下面还需要二重判断
                        nowTime = std::chrono::high_resolution_clock::now();
                        if (this->nowTaskNum_ <= 0 && this->nowThreadNum_ > this->initThreadNum_ && std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - lastTime).count() > this->cache_wait_milliseconds) {
                            break;
                        }
                        // 当线程被唤醒时优先判断队列是否非空，
                        this->notEmpty_cv.wait_for(lock, std::chrono::seconds(1));
                    }
                    else {
                        this->notEmpty_cv.wait(lock);
                    }
                }
                if (this->nowTaskNum_ <= 0) {
                    this->destroyThread(id);
                    this->nowThreadNum_--;
                    this->notThread_cv.notify_all();
                    break;
                }
                assert(this->nowTaskNum_ > 0);

                task = std::move(this->taskQue_.front());
                this->taskQue_.pop();
                this->nowTaskNum_--;
                this->notFull_cv.notify_all();
            }
            task();
            lastTime = std::chrono::high_resolution_clock::now();
        }
    }

    ThreadPool::~ThreadPool() {
        this->isEnd = true;
        std::unique_lock<std::mutex>lock(this->mx_lock);
        while(this->nowThreadNum_ > 0){
            //下面两句不能颠倒，否则会造成死锁，因为如果然主线程先进入等待状态而其他线程同样也处于等待状态时，那样所有的线程都无法被唤醒
            this->notEmpty_cv.notify_all();
            this->notThread_cv.wait(lock);

        }
    }

    void ThreadPool::setInitThreadNum(size_t initThreadNum) {
        initThreadNum_ = initThreadNum;
    }

    void ThreadPool::setMaxThreadNum(size_t maxThreadNum) {
        maxThreadNum_ = maxThreadNum;
    }

    void ThreadPool::setMaxTaskNum(size_t maxTaskNum) {
        maxTaskNum_ = maxTaskNum;
    }

    void ThreadPool::setMode(ThreadPoolMode mode) {
        ThreadPool::mode = mode;
    }

    // Thread /////////////////////////////////////////////

    void Thread::start() {
        this->td = new std::thread(this->func);
        this->td->detach();
    }

    Thread::Thread(Thread::ThreadFunc func) : func(std::move(func)) {}

    uint32_t Thread::getNowId() {
        return Thread::nowId++;
    }

    uint32_t Thread::getUid() const {
        return uid;
    }

    Thread::~Thread() {
        delete this->td;
    }

    // CwjSemaphore ///////////////////////////////////////////////////////

    void CwjSemaphore::wait() {
        std::unique_lock<std::mutex>lock(this->mx_lock);
        this->cv.wait(lock, [this] {return this->src_num > 0;});
        this->src_num--;
    }
    void CwjSemaphore::post() {
        std::unique_lock<std::mutex>lock(this->mx_lock);
        this->src_num++;
        this->cv.notify_all();
    }

    // Task //////////////////////////////////////////////////////////

    template<>
    void Task<void>::exec() {
        this->func();
    };

}


